<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
	<title>高级脚本使用脚本引擎 | ElasticSearch 7.7 权威指南中文版</title>
	<meta name="keywords" content="ElasticSearch 权威指南中文版, elasticsearch 7, es7, 实时数据分析，实时数据检索" />
    <meta name="description" content="ElasticSearch 权威指南中文版, elasticsearch 7, es7, 实时数据分析，实时数据检索" />
    <!-- Give IE8 a fighting chance -->
    <!--[if lt IE 9]>
    <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
    <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->
	<link rel="stylesheet" type="text/css" href="../static/styles.css" />
	<script>
	var _link = 'modules-scripting-engine.html';
    </script>
</head>
<body>
<div class="main-container">
    <section id="content">
        <div class="content-wrapper">
            <section id="guide" lang="zh_cn">
                <div class="container">
                    <div class="row">
                        <div class="col-xs-12 col-sm-8 col-md-8 guide-section">
                            <div style="color:gray; word-break: break-all; font-size:12px;">原英文版地址: <a href="https://www.elastic.co/guide/en/elasticsearch/reference/7.7/modules-scripting-engine.html" rel="nofollow" target="_blank">https://www.elastic.co/guide/en/elasticsearch/reference/7.7/modules-scripting-engine.html</a>, 原文档版权归 www.elastic.co 所有<br/>本地英文版地址: <a href="../en/modules-scripting-engine.html" rel="nofollow" target="_blank">../en/modules-scripting-engine.html</a></div>
                        <!-- start body -->
                  <div class="page_header">
<strong>重要</strong>: 此版本不会发布额外的bug修复或文档更新。最新信息请参考 <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html" rel="nofollow">当前版本文档</a>。
</div>
<div id="content">
<div class="breadcrumbs">
<span class="breadcrumb-link"><a href="index.html">Elasticsearch 权威指南 [7.7]</a></span>
»
<span class="breadcrumb-link"><a href="modules-scripting.html">脚本</a></span>
»
<span class="breadcrumb-node">高级脚本使用脚本引擎</span>
</div>
<div class="navheader">
<span class="prev">
<a href="modules-scripting-expression.html">« Lucene表达式语言</a>
</span>
<span class="next">
<a href="mapping.html">映射 »</a>
</span>
</div>
<div class="chapter">
<div class="titlepage"><div><div>
<h2 class="title">
<a id="modules-scripting-engine"></a>高级脚本使用脚本引擎
</h2>
</div></div></div>
<p>
<code class="literal">ScriptEngine</code>是实现脚本语言的后端。

它还可以用来编写需要使用高级脚本内部机制的脚本。

例如，一个脚本希望在评分时使用词项的频率。
</p>
<p>
<a href="https://www.elastic.co/guide/en/elasticsearch/plugins/7.7/plugin-authors.html" class="ulink" target="_top">插件文档</a>中有更多关于如何编写插件的信息，这样Elasticsearch就可以正确地加载它。

要注册<code class="literal">ScriptEngine</code>，插件应该实现<code class="literal">ScriptPlugin</code>接口并重写<code class="literal">getScriptEngine(Settings settings)</code>方法。
</p>
<p>
下面是一个使用语言名称为<code class="literal">expert_scripts</code>的自定义脚本引擎的示例。

它实现了一个名为<code class="literal">pure_df</code>的脚本，该脚本可以用作搜索脚本来覆盖每个文档的分数，作为所提供词项的文档频率。
</p>
<div class="pre_wrapper lang-java">
<pre class="programlisting prettyprint lang-java">private static class MyExpertScriptEngine implements ScriptEngine {
    @Override
    public String getType() {
        return "expert_scripts";
    }

    @Override
    public &lt;T&gt; T compile(
        String scriptName,
        String scriptSource,
        ScriptContext&lt;T&gt; context,
        Map&lt;String, String&gt; params
    ) {
        if (context.equals(ScoreScript.CONTEXT) == false) {
            throw new IllegalArgumentException(getType()
                    + " scripts cannot be used for context ["
                    + context.name + "]");
        }
        // we use the script "source" as the script identifier
        if ("pure_df".equals(scriptSource)) {
            ScoreScript.Factory factory = new PureDfFactory();
            return context.factoryClazz.cast(factory);
        }
        throw new IllegalArgumentException("Unknown script name "
                + scriptSource);
    }

    @Override
    public void close() {
        // optionally close resources
    }

    @Override
    public Set&lt;ScriptContext&lt;?&gt;&gt; getSupportedContexts() {
        return Collections.singleton(ScoreScript.CONTEXT);
    }

    private static class PureDfFactory implements ScoreScript.Factory,
                                                  ScriptFactory {
        @Override
        public boolean isResultDeterministic() {
            // PureDfLeafFactory only uses deterministic APIs, this
            // implies the results are cacheable.
            return true;
        }

        @Override
        public LeafFactory newFactory(
            Map&lt;String, Object&gt; params,
            SearchLookup lookup
        ) {
            return new PureDfLeafFactory(params, lookup);
        }
    }

    private static class PureDfLeafFactory implements LeafFactory {
        private final Map&lt;String, Object&gt; params;
        private final SearchLookup lookup;
        private final String field;
        private final String term;

        private PureDfLeafFactory(
                    Map&lt;String, Object&gt; params, SearchLookup lookup) {
            if (params.containsKey("field") == false) {
                throw new IllegalArgumentException(
                        "Missing parameter [field]");
            }
            if (params.containsKey("term") == false) {
                throw new IllegalArgumentException(
                        "Missing parameter [term]");
            }
            this.params = params;
            this.lookup = lookup;
            field = params.get("field").toString();
            term = params.get("term").toString();
        }

        @Override
        public boolean needs_score() {
            return false;  // Return true if the script needs the score
        }

        @Override
        public ScoreScript newInstance(LeafReaderContext context)
                throws IOException {
            PostingsEnum postings = context.reader().postings(
                    new Term(field, term));
            if (postings == null) {
                /*
                 * the field and/or term don't exist in this segment,
                 * so always return 0
                 */
                return new ScoreScript(params, lookup, context) {
                    @Override
                    public double execute(
                        ExplanationHolder explanation
                    ) {
                        return 0.0d;
                    }
                };
            }
            return new ScoreScript(params, lookup, context) {
                int currentDocid = -1;
                @Override
                public void setDocument(int docid) {
                    /*
                     * advance has undefined behavior calling with
                     * a docid &lt;= its current docid
                     */
                    if (postings.docID() &lt; docid) {
                        try {
                            postings.advance(docid);
                        } catch (IOException e) {
                            throw new UncheckedIOException(e);
                        }
                    }
                    currentDocid = docid;
                }
                @Override
                public double execute(ExplanationHolder explanation) {
                    if (postings.docID() != currentDocid) {
                        /*
                         * advance moved past the current doc, so this
                         * doc has no occurrences of the term
                         */
                        return 0.0d;
                    }
                    try {
                        return postings.freq();
                    } catch (IOException e) {
                        throw new UncheckedIOException(e);
                    }
                }
            };
        }
    }
}</pre>
</div>
<p>可以通过将脚本的<code class="literal">lang</code>指定为<code class="literal">expert_scripts</code>，并将脚本的名称指定为脚本源来执行脚本：</p>
<div class="pre_wrapper lang-console">
<pre class="programlisting prettyprint lang-console">POST /_search
{
  "query": {
    "function_score": {
      "query": {
        "match": {
          "body": "foo"
        }
      },
      "functions": [
        {
          "script_score": {
            "script": {
                "source": "pure_df",
                "lang" : "expert_scripts",
                "params": {
                    "field": "body",
                    "term": "foo"
                }
            }
          }
        }
      ]
    }
  }
}</pre>
</div>
<div class="console_widget" data-snippet="snippets/602.console"></div>
</div>
<div class="navfooter">
<span class="prev">
<a href="modules-scripting-expression.html">« Lucene表达式语言</a>
</span>
<span class="next">
<a href="mapping.html">映射 »</a>
</span>
</div>
</div>

                  <!-- end body -->
                        </div>
                        <div class="col-xs-12 col-sm-4 col-md-4" id="right_col">
                        
                        </div>
                    </div>
                </div>
            </section>
        </div>
    </section>
</div>
<script src="../static/cn.js"></script>
</body>
</html>